use std::{fs, io::{BufRead, BufReader, Write}, net::{TcpListener, TcpStream}, thread, time::Duration};
use rs_webserver_thread::ThreadPool;

fn main() {
    println!("Webserver thread...!");
    let listener = TcpListener::bind("127.0.0.1:9999").unwrap();

    // 限制线程数量
    let pool = ThreadPool::new(4);

    // 阻塞监听
    // 一个问题：如果同一个连接发送了多个http请求的话，他会自动分为两个stream吗？
    // 答： 不会。
    // 原因：TcpStream 是基于 TCP 协议的流式连接，而 TCP 本身是面向流的协议，不具有消息边界的概念。
    // 所以：在一个 TCP 连接中，多个 HTTP 请求可能会连续发送，服务器需要自己解析这些请求并正确处理。
    // -------
    // 目前我们按照简单的方法处理：每次读取Tcp流的内容直到碰到空行，也就是说只处理第一个请求。
    // 处理多个请求的case参考：https://lxblog.com/qianwen/share?shareId=fcf8e2e0-a2ad-4425-830e-d62123f55cfa
    for stream in listener.incoming().take(2) {
        let stream = stream.unwrap();
        println!("Connection established");

        // 将连接的处理投入到子线程中去
        // thread::spawn(move|| {
        //     handle_connection(stream);
        // });

        pool.execute(move|| {
            handle_connection(stream);
        });
    }
}

fn handle_connection(mut stream: TcpStream) {
    let buf_reader = BufReader::new(&mut stream);
    // lines 会返回一个迭代器，每次读取一行时，结果是 Result<String, std::io::Error>
    // 其后的map/take_while都是迭代器的适配器，针对迭代器的每一项进行操作; /collect 是迭代器消费者。
    // map： 将该Result做unwrap解开操作，提取String
    // take_while 收集map操作的每一项结果（一旦take_while碰到false，就不再处理当前和后续的元素
    let http_request: Vec<_> = buf_reader.lines().map(|l|l.unwrap()).
    take_while(|l|!l.is_empty()).collect();

    // 请求内容应该形如：
    // Request: [
    //   "GET / HTTP/1.1",
    //   "Host: 127.0.0.1:9999",
    //   "User-Agent: curl/7.61.1",
    //   "Accept: */*",
    // ]
    println!("Request: {:#?}", http_request); // 此处只是借用了一下，不会转移所有权
    println!("Request[0]: {:#?}", http_request[0]);

    // 响应客户端，形如
    // HTTP-Version Status-Code Reason-Phrase CRLF
    // headers CRLF
    // 
    // message-body

    let (status_line, filename) = match &http_request[0][..] {
        "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "html/hello.html"),
        "GET /sleep HTTP/1.1" => {
            // 模拟慢请求，睡上5秒中
            thread::sleep(Duration::from_secs(5));
            ("HTTP/1.1 200 OK", "html/sleep.html")
        },
        _ => ("HTTP/1.1 404 NOT FOUND", "html/404.html"),
    };

    // 构造message-body
    let content = fs::read_to_string(filename).unwrap();
    let length = content.len();
    let response = format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{content}");
    // write_all方法接收 &[u8] 类型作为参数。
    stream.write_all(response.as_bytes()).unwrap();

}
